home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
TECHNICA
/
COMPUTER
/
H254.ZIP
/
IRITSM3S.ZIP
/
IRIT
/
DATAPRSR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-29
|
35KB
|
1,165 lines
/*****************************************************************************
* "Irit" - the 3d polygonal solid modeller. *
* *
* Written by: Gershon Elber Ver 0.2, Mar. 1990 *
******************************************************************************
* Data File Interpreter module - handle data files - to/from geom objects *
*****************************************************************************/
#ifdef USE_VARARGS
#include <varargs.h>
#else
#include <stdarg.h>
#endif /* USE_VARARGS */
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include "program.h"
#include "cagd_lib.h"
#include "allocate.h"
#include "attribut.h"
#include "dataprsr.h" /* Visible to the other modules. */
#include "geomat3d.h"
#include "objects.h"
#include "windows.h"
#include "graphgen.h"
#define UNGET_STACK_SIZE 5 /* Internal stack size. */
typedef enum { /* List of all possible tokens enumerated. */
TOKEN_NONE,
TOKEN_OPEN_PAREN,
TOKEN_CLOSE_PAREN,
TOKEN_E2,
TOKEN_P2,
TOKEN_E3,
TOKEN_P3,
TOKEN_NUMBER,
TOKEN_STRING,
TOKEN_VECTOR,
TOKEN_MATRIX,
TOKEN_CTLPT,
TOKEN_VERTEX,
TOKEN_POLYGON,
TOKEN_POLYLINE,
TOKEN_OBJECT,
TOKEN_COLOR,
TOKEN_INTERNAL,
TOKEN_NORMAL,
TOKEN_PLANE,
TOKEN_CURVE,
TOKEN_SURFACE,
TOKEN_OTHER = 100, /* Probably names & numbers. */
TOKEN_EOF = -1
} TokenType;
typedef enum { /* Possible error code during data parsing. */
DP_NO_ERR = 0,
DP_ERR_NUMBER_EXPECTED,
DP_ERR_OPEN_PAREN_EXPECTED,
DP_ERR_CLOSE_PAREN_EXPECTED,
DP_ERR_LIST_COMP_UNDEF,
DP_ERR_UNDEF_EXPR_HEADER,
DP_ERR_PT_TYPE_EXPECTED,
DP_ERR_OBJECT_EMPTY,
DP_ERR_EMPTY_NAME,
DP_ERR_OPEN_FAILED,
DP_ERR_MIXED_TYPES,
DP_STR_NOT_IN_QUOTES,
DP_ERR_CAGD_LIB_ERR,
DP_WRN_OBJ_NAME_TRUNC = 100
} DataPrsrErrType;
static int DPGlblLineCount = 0; /* Used to locate errors in input file. */
static DataPrsrErrType DPGlblParserError = DP_NO_ERR; /* Last err # found. */
static char DPGlblTokenError[LINE_LEN]; /* Last token where error was found. */
static jmp_buf LclLongJumpBuffer; /* Used in error traping. */
static int GlblToken = 0, /* Used by the parser, to unget token. */
GlblLineCount = 1; /* Used to locate errors in input file. */
static char GlblStringToken[UNGET_STACK_SIZE][LINE_LEN];/* Save unget tokens.*/
static FILE *OutputFile = NULL;
static void UnGetToken(char *StringToken);
static void GetStringToken(FILE *f, char *StringToken);
static TokenType GetToken(FILE *f, char *StringToken);
static void GetVertexAttributes(VertexStruct *PVertex, FILE *f,
int *HasNormal);
static void GetPolygonAttributes(PolygonStruct *PPolygon, FILE *f,
int *HasPlane);
static void GetObjectAttributes(ObjectStruct *PObject, FILE *f);
static void GetPointData(FILE *f, PolygonStruct *PPolygon, int IsPolyline,
int *HasNormal);
static void DPUpdatePolyPlane(PolygonStruct *PPoly);
static void ParserError(DataPrsrErrType ErrNum, char *Msg);
static void DataPrsrPutAllObjects(ObjectStruct *PObj, int Indent);
static char *Real2Str(RealType R);
static void DataPrsrGetAllObjects(FILE *f, ObjectStruct *PObjParent);
static void GetCloseParenToken(FILE *f);
static void GetNumericToken(FILE *f, RealType *r);
static void DataPrsrGetAuxObject(FILE *f, ObjectStruct *PObj);
#ifdef USE_VARARGS
static void IFprintf(int Indent, char *va_alist, ...);
#else
static void IFprintf(int Indent, char *Format, ...);
#endif /* USE_VARARGS */
/*****************************************************************************
* Routine to print the data from given object into given file FileName. *
* If FileName is NULL or empty, print to screen using WndwInputWindowPutStr. *
*****************************************************************************/
void DataPrsrPutObject(char *FileName, ObjectStruct *PObj)
{
char *Pchar;
char FullFileName[LINE_LEN];
DPGlblParserError = DP_NO_ERR;
/* If the following gain control and is non zero - its from error! */
if (setjmp(LclLongJumpBuffer) != 0) {
if (OutputFile != NULL) fclose(OutputFile);
return;
}
if (FileName && (int) strlen(FileName) > 0) {
if ((Pchar = strchr(FileName, '.')) != NULL)
*Pchar = 0; /* Make sure no file type is given. */
if (strlen(FileName) == 0) ParserError(DP_ERR_EMPTY_NAME, "");
strcpy(FullFileName, FileName);
strcat(FullFileName, ".dat");
if ((OutputFile = fopen(FullFileName, "w")) == NULL)
ParserError(DP_ERR_OPEN_FAILED, FullFileName);
}
else
OutputFile = NULL;
DataPrsrPutAllObjects(PObj, 0);
if (OutputFile) {
fclose(OutputFile);
OutputFile = NULL;
}
return;
}
/*****************************************************************************
* Routine to read the data from a given file. *
*****************************************************************************/
ObjectStruct *DataPrsrGetObjects(char *FileName)
{
char FullFileName[LINE_LEN];
FILE
*f = NULL;
ObjectStruct *PObj, *PTmp;
/* If the following gain control and is non zero - its from error! */
if (setjmp(LclLongJumpBuffer) != 0) {
if (f != NULL) fclose(f);
return NULL;
}
if (strlen(FileName) == 0) ParserError(DP_ERR_EMPTY_NAME, "");
strcpy(FullFileName, FileName);
if (strrchr(FullFileName, '.') == NULL) strcat(FullFileName, ".dat");
if ((f = fopen(FullFileName, "r")) == NULL)
ParserError(DP_ERR_OPEN_FAILED, FullFileName);
GlblToken = 0; /* Used in UnGetToken token buffer. */
DPGlblParserError = DP_NO_ERR; /* Reset errors. */
GlblLineCount = 1; /* Reset line counter. */
PObj = AllocObject("", OBJ_LIST_OBJ, NULL);
DataPrsrGetAllObjects(f, PObj);
if (PObj -> ObjType == OBJ_LIST_OBJ &&
PObj -> U.PObjList[1] == NULL)
{
/* Only one object in list - return the object instead. */
PTmp = PObj -> U.PObjList[0];
PObj -> U.PObjList[0] = NULL;
MyFree((char *) PObj, ALLOC_OBJECT);
PObj = PTmp;
}
fclose(f);
return PObj;
}
/*****************************************************************************
* Same as fprintf but with indentation. Prints into global OutputFile unless *
* it is NULL in which it prints to screen using WndwInputWindowPutStr *
*****************************************************************************/
#ifdef USE_VARARGS
static void IFprintf(int Indent, char *va_alist, ...)
{
char *Format, Line[LINE_LEN_LONG];
int i;
va_list ArgPtr;
va_start(ArgPtr);
Format = va_arg(ArgPtr, char *);
#else
static void IFprintf(int Indent, char *Format, ...)
{
char Line[LINE_LEN_LONG];
int i;
va_list ArgPtr;
va_start(ArgPtr, Format);
#endif /* USE_VARARGS */
for (i = 0; i < Indent; i++) Line[i] = ' ';
vsprintf(&Line[Indent], Format, ArgPtr);
va_end(ArgPtr);
if (OutputFile != NULL)
fputs(Line, OutputFile);
else
WndwInputWindowPutStr(Line);
}
/*****************************************************************************
* Routine to print the data from given geometry object. *
*****************************************************************************/
static void DataPrsrPutAllObjects(ObjectStruct *PObj, int Indent)
{
int i;
char
*ErrStr = NULL;
CagdRType *Coords;
PolygonStruct *PPolygon;
VertexStruct *PVertex;
if (IS_GEOM_OBJ(PObj)) {
AttributeStruct
*Attr = &(PObj -> U.Attr);
IFprintf(Indent, "[OBJECT [COLOR %d]", GetObjectColor(PObj));
if (Attr -> NumStrAttribs > 0) {
IFprintf(0, "\n");
for (i = 0; i < Attr -> NumStrAttribs; i++)
IFprintf(Indent + 8,
i == Attr -> NumStrAttribs - 1 ? "[%s %s]" : "[%s %s]\n",
Attr -> StrAttrName[i], Attr -> StrAttrData[i]);
IFprintf(0, " %s\n",
strlen(PObj -> Name) ? PObj -> Name : "NONE");
}
else
IFprintf(0, " %s\n",
strlen(PObj -> Name) ? PObj -> Name : "NONE");
}
else
IFprintf(Indent, "[OBJECT %s\n",
strlen(PObj -> Name) ? PObj -> Name : "NONE");
Indent += 4;
switch (PObj -> ObjType) {
case POLY_OBJ:
for (PPolygon = PObj -> U.Pl.P;
PPolygon != NULL;
PPolygon = PPolygon -> Pnext) {
if (PPolygon -> V == NULL)
FatalError("Dump: Attemp to dump empty polygon, exit\n");
for (PVertex = PPolygon -> V -> Pnext, i = 1;
PVertex != PPolygon -> V && PVertex != NULL;
PVertex = PVertex -> Pnext, i++);
if (IS_POLYLINE_OBJ(PObj))
IFprintf(Indent, "[POLYLINE %d\n", i);
else
IFprintf(Indent, "[POLYGON [PLANE %s %s %s %s] %d\n",
Real2Str(PPolygon -> Plane[0]),
Real2Str(PPolygon -> Plane[1]),
Real2Str(PPolygon -> Plane[2]),
Real2Str(PPolygon -> Plane[3]), i);
PVertex = PPolygon -> V;
do { /* Assume at least one edge in polygon! */
if (IS_POLYLINE_OBJ(PObj))
IFprintf(Indent + 4, "[%s%s %s %s]\n",
IS_INTERNAL_EDGE(PVertex) ? "[INTERNAL] " : "",
Real2Str(PVertex -> Pt[0]),
Real2Str(PVertex -> Pt[1]),
Real2Str(PVertex -> Pt[2]));
else
IFprintf(Indent + 4, "[%s[NORMAL %s %s %s] %s %s %s]\n",
IS_INTERNAL_EDGE(PVertex) ? "[INTERNAL] " : "",
Real2Str(PVertex -> Normal[0]),
Real2Str(PVertex -> Normal[1]),
Real2Str(PVertex -> Normal[2]),
Real2Str(PVertex -> Pt[0]),
Real2Str(PVertex -> Pt[1]),
Real2Str(PVertex -> Pt[2]));
PVertex = PVertex -> Pnext;
}
while (PVertex != PPolygon -> V && PVertex != NULL);
IFprintf(Indent, "]\n"); /* Close the polygon. */
}
break;
case NUMERIC_OBJ:
IFprintf(Indent, "[NUMBER %s]\n", Real2Str(PObj -> U.R));
break;
case VECTOR_OBJ:
IFprintf(Indent, "[VECTOR %s %s %s]\n",
Real2Str(PObj -> U.Vec[0]),
Real2Str(PObj -> U.Vec[1]),
Real2Str(PObj -> U.Vec[2]));
break;
case CTLPT_OBJ:
Coords = PObj -> U.CtlPt.Coords;
switch (PObj -> U.CtlPt.PtType) {
case CAGD_PT_E2_TYPE:
IFprintf(Indent, "[CTLPT %s %s %s]\n", "E2",
Real2Str(Coords[1]),
Real2Str(Coords[2]));
break;
case CAGD_PT_P2_TYPE:
IFprintf(Indent, "[CTLPT %s %s %s %s]\n", "P2",
Real2Str(Coords[0]),
Real2Str(Coords[1]),
Real2Str(Coords[2]));
break;
case CAGD_PT_E3_TYPE:
IFprintf(Indent, "[CTLPT %s %s %s %s]\n", "E3",
Real2Str(Coords[1]),
Real2Str(Coords[2]),
Real2Str(Coords[3]));
break;
case CAGD_PT_P3_TYPE:
IFprintf(Indent, "[CTLPT %s %s %s %s %s]\n", "P3",
Real2Str(Coords[0]),
Real2Str(Coords[1]),
Real2Str(Coords[2]),
Real2Str(Coords[3]));
break;
default:
WndwInputWindowPutStr("Dump: Undefined point type");
break;
}
break;
case MATRIX_OBJ:
IFprintf(Indent, "[MATRIX\n");
for (i = 0; i < 4; i++)
IFprintf(Indent + 8, "%s %s %s %s%s\n",
Real2Str(PObj -> U.Mat[i][0]),
Real2Str(PObj -> U.Mat[i][1]),
Real2Str(PObj -> U.Mat[i][2]),
Real2Str(PObj -> U.Mat[i][3]),
i == 3 ? "]" : "");
break;
case STRING_OBJ:
IFprintf(Indent, "[STRING \"%s\"]\n", PObj -> U.Str);
break;
case OBJ_LIST_OBJ:
for (i = 0; PObj -> U.PObjList[i] != NULL; i++)
DataPrsrPutAllObjects(PObj -> U.PObjList[i], Indent);
break;
case CURVE_OBJ:
CagdCrvWriteToFile2(PObj -> U.Crv.Crv, OutputFile, Indent, NULL, &ErrStr);
break;
case SURFACE_OBJ:
CagdSrfWriteToFile2(PObj -> U.Srf.Srf, OutputFile, Indent, NULL, &ErrStr);
break;
default:
WndwInputWindowPutStr(
"Dump: Attemp to dump undefine object type.");
break;
}
Indent -= 4;
IFprintf(Indent, "]\n"); /* Close the object. */
if (ErrStr != NULL) ParserError(DP_ERR_CAGD_LIB_ERR, ErrStr);
}
/*****************************************************************************
* Convert a real number into a string. *
* The routine maintains 6 different buffers simultanuously so up to 6 calls *
* can be issued from same printf... *
*****************************************************************************/
static char *Real2Str(RealType R)
{
static int j, k,
i = 0;
static char Buffer[6][LINE_LEN_SHORT], Line[LINE_LEN];
if (ABS(R) < EPSILON) R = 0.0; /* Round off very small numbers. */
# ifdef DOUBLE
sprintf(Buffer[i], "%-8.6lg", R);
# else
sprintf(Buffer[i], "%-8.6g", R);
# endif /* DOUBLE */
for (k = 0; !isdigit(Buffer[i][k]) && k < LINE_LEN; k++);
if (k >= LINE_LEN) {
sprintf(Line, "Conversion of real number (%f) failed.\n", R);
FatalError(Line);
}
for (j = strlen(Buffer[i]) - 1; Buffer[i][j] == ' ' && j > k; j--);
if (strchr(Buffer[i], '.') != NULL)
for (; Buffer[i][j] == '0' && j > k; j--);
Buffer[i][j+1] = 0;
j = i;
i = (i + 1) % 6;
return Buffer[j];
}
/*****************************************************************************
* Routine to read the geometry data from a given file. Reads "[OBJECT ..." *
* prefixes only and invoke the auxiliary routine. *
* Note objects may be recursively defined. *
*****************************************************************************/
static void DataPrsrGetAllObjects(FILE *f, ObjectStruct *PObjParent)
{
char StringToken[LINE_LEN];
TokenType Token;
int ObjCount = 0,
Quit = FALSE;
ObjectStruct *PObj, *OldPObj;
while (!Quit) {
while ((Token = GetToken(f, StringToken)) != TOKEN_OPEN_PAREN &&
Token != TOKEN_CLOSE_PAREN &&
Token != TOKEN_EOF);
if (Token == TOKEN_CLOSE_PAREN || Token == TOKEN_EOF)
{
if (Token == TOKEN_CLOSE_PAREN)
UnGetToken(StringToken);
Quit = TRUE;
break;
}
switch (GetToken(f, StringToken)) {
case TOKEN_OBJECT:
PObjParent -> ObjType = OBJ_LIST_OBJ;
PObj = AllocObject("", UNDEF_OBJ, NULL);
/* The following handle optional attributes in record. */
if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
GetObjectAttributes(PObj, f);
else
{
SetObjectColor(PObj, GlblLoadColor);
UnGetToken(StringToken);
}
if (GetToken(f, StringToken) == TOKEN_OTHER &&
strcmp(StringToken, "NONE") != 0)
strcpy(PObj -> Name, StringToken);
DataPrsrGetAllObjects(f, PObj);
GetCloseParenToken(f);
if (PObj -> ObjType == UNDEF_OBJ)
ParserError(DP_ERR_OBJECT_EMPTY, "");
PObjParent -> U.PObjList[ObjCount++] = PObj;
if ((int) strlen(PObj -> Name) > 0) {
if ((OldPObj = GetObject(PObj -> Name)) != NULL)
DeleteObject(OldPObj, TRUE);
InsertObject(PObj);
PObj -> Count++;
}
break;
default:
UnGetToken(StringToken);
UnGetToken("[");
DataPrsrGetAuxObject(f, PObjParent);
Quit = TRUE;
break;
}
}
if (PObjParent -> ObjType == UNDEF_OBJ)
ParserError(DP_ERR_OBJECT_EMPTY, "");
else if (PObjParent -> ObjType == OBJ_LIST_OBJ)
PObjParent -> U.PObjList[ObjCount++] = NULL;
}
/*****************************************************************************
* Routine to get close paren token from f. *
*****************************************************************************/
static void GetCloseParenToken(FILE *f)
{
char StringToken[LINE_LEN];
if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN)
ParserError(DP_ERR_CLOSE_PAREN_EXPECTED, StringToken);
}
/*****************************************************************************
* Routine to get one numeric token into r. *
*****************************************************************************/
static void GetNumericToken(FILE *f, RealType *r)
{
char StringToken[LINE_LEN];
GetToken(f, StringToken);
# ifdef DOUBLE
if (sscanf(StringToken, "%lf", r) != 1)
# else
if (sscanf(StringToken, "%f", r) != 1)
# endif /* DOUBLE */
ParserError(DP_ERR_NUMBER_EXPECTED, StringToken);
}
/*****************************************************************************
* Routine to read the geometry data from a given file. *
*****************************************************************************/
static void DataPrsrGetAuxObject(FILE *f, ObjectStruct *PObj)
{
int i, j, ErrLine, HasPlane, HasNormal;
char *p1, *p2, *ErrStr, StringToken[LINE_LEN];
CagdRType *Coords;
VertexStruct *PVertex;
PolygonStruct *PPolygon;
CagdCrvStruct *PCurve;
CagdSrfStruct *PSurface;
while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN) {
switch (GetToken(f, StringToken)) {
case TOKEN_POLYLINE:
switch (PObj -> ObjType) {
case POLY_OBJ:
if (!IS_POLYLINE_OBJ(PObj))
ParserError(DP_ERR_MIXED_TYPES, "");
break;
case UNDEF_OBJ:
PObj -> ObjType = POLY_OBJ;
PObj -> U.Pl.P = NULL;
SET_POLYLINE_OBJ(PObj);
break;
default:
ParserError(DP_ERR_MIXED_TYPES, "");
break;
}
PPolygon = AllocPolygon(0, 0, NULL, NULL);
/* The following handle the optional attributes in struct. */
if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
GetPolygonAttributes(PPolygon, f, &HasPlane);
else
UnGetToken(StringToken);
/* The following handles reading the vertices. */
GetPointData(f, PPolygon, TRUE, &HasNormal);
PPolygon -> Pnext = PObj -> U.Pl.P;
PObj -> U.Pl.P = PPolygon;
break;
case TOKEN_POLYGON:
switch (PObj -> ObjType) {
case POLY_OBJ:
if (IS_POLYLINE_OBJ(PObj))
ParserError(DP_ERR_MIXED_TYPES, "");
break;
case UNDEF_OBJ:
PObj -> ObjType = POLY_OBJ;
PObj -> U.Pl.P = NULL;
RST_POLYLINE_OBJ(PObj);
break;
default:
ParserError(DP_ERR_MIXED_TYPES, "");
break;
}
PPolygon = AllocPolygon(0, 0, NULL, NULL);
/* The following handle the optional attributes in struct. */
HasPlane = HasNormal = FALSE;
if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
GetPolygonAttributes(PPolygon, f, &HasPlane);
else
UnGetToken(StringToken);
/* The following handles reading the vertices. */
GetPointData(f, PPolygon, FALSE, &HasNormal);
if (!HasPlane) DPUpdatePolyPlane(PPolygon);
if (!HasNormal) {
/* Update all normals to be the same as plane eqn. */
PVertex = PPolygon -> V;
do {
PT_COPY(PVertex -> Normal, PPolygon -> Plane);
PVertex = PVertex -> Pnext;
}
while (PVertex != PPolygon -> V && PVertex != NULL);
}
PPolygon -> Pnext = PObj -> U.Pl.P;
PObj -> U.Pl.P = PPolygon;
break;
case TOKEN_NUMBER:
switch (PObj -> ObjType) {
case NUMERIC_OBJ:
break;
case UNDEF_OBJ:
PObj -> ObjType = NUMERIC_OBJ;
break;
default:
ParserError(DP_ERR_MIXED_TYPES, "");
break;
}
GetNumericToken(f, &PObj -> U.R);
GetCloseParenToken(f);
break;
case TOKEN_STRING:
switch (PObj -> ObjType) {
case STRING_OBJ:
break;
case UNDEF_OBJ:
PObj -> ObjType = STRING_OBJ;
break;
default:
ParserError(DP_ERR_MIXED_TYPES, "");
break;
}
GetToken(f, StringToken);
if ((p1 = strchr(StringToken, '"')) == NULL ||
(p2 = strrchr(StringToken, '"')) == p1)
ParserError(DP_STR_NOT_IN_QUOTES, StringToken);
/* Convert the end quote to EOS and copy string. */
*p2 = 0;
strcpy(PObj -> U.Str, &p1[1]);
GetCloseParenToken(f);
break;
case TOKEN_VECTOR:
switch (PObj -> ObjType) {
case VECTOR_OBJ:
break;
case UNDEF_OBJ:
PObj -> ObjType = VECTOR_OBJ;
break;
default:
ParserError(DP_ERR_MIXED_TYPES, "");
break;
}
for (i = 0; i < 3; i++)
GetNumericToken(f, &PObj -> U.Vec[i]);
GetCloseParenToken(f);
break;
case TOKEN_MATRIX:
switch (PObj -> ObjType) {
case MATRIX_OBJ:
break;
case UNDEF_OBJ:
PObj -> ObjType = MATRIX_OBJ;
break;
default:
ParserError(DP_ERR_MIXED_TYPES, "");
break;
}
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++)
GetNumericToken(f, &PObj -> U.Mat[i][j]);
GetCloseParenToken(f);
break;
case TOKEN_CTLPT:
switch (PObj -> ObjType) {
case CTLPT_OBJ:
break;
case UNDEF_OBJ:
PObj -> ObjType = CTLPT_OBJ;
break;
default:
ParserError(DP_ERR_MIXED_TYPES, "");
break;
}
switch (GetToken(f, StringToken)) {
case TOKEN_E2:
PObj -> U.CtlPt.PtType = CAGD_PT_E2_TYPE;
j = 2;
i = 1;
break;
case TOKEN_P2:
PObj -> U.CtlPt.PtType = CAGD_PT_P2_TYPE;
j = 3;
i = 0;
break;
case TOKEN_E3:
PObj -> U.CtlPt.PtType = CAGD_PT_E3_TYPE;
j = 3;
i = 1;
break;
case TOKEN_P3:
PObj -> U.CtlPt.PtType = CAGD_PT_P3_TYPE;
j = 4;
i = 0;
break;
default:
WndwInputWindowPutStr("Read: Undefined point type");
break;
}
Coords = PObj -> U.CtlPt.Coords;
for ( ; j > 0; i++, j--)
GetNumericToken(f, &Coords[i]);
GetCloseParenToken(f);
break;
case TOKEN_SURFACE:
switch (PObj -> ObjType) {
case SURFACE_OBJ:
break;
case UNDEF_OBJ:
PObj -> ObjType = SURFACE_OBJ;
PObj -> U.Srf.Srf = NULL;
PObj -> U.Srf.PLPolys = NULL;
PObj -> U.Srf.CtlMesh = NULL;
PObj -> U.Srf.Polygons = NULL;
break;
default:
ParserError(DP_ERR_MIXED_TYPES, "");
break;
}
ErrLine = GlblLineCount;
PSurface = CagdSrfReadFromFile2(f, &ErrStr, &ErrLine);
GlblLineCount = ErrLine;
if (ErrStr != NULL) {
ParserError(DP_ERR_CAGD_LIB_ERR, ErrStr);
break;
}
PSurface -> Pnext = PObj -> U.Srf.Srf;
PObj -> U.Srf.Srf = PSurface;
break;
case TOKEN_CURVE:
switch (PObj -> ObjType) {
case CURVE_OBJ:
break;
case UNDEF_OBJ:
PObj -> ObjType = CURVE_OBJ;
PObj -> U.Crv.Crv = NULL;
PObj -> U.Crv.PLPolys = NULL;
PObj -> U.Crv.CtlPoly = NULL;
break;
default:
ParserError(DP_ERR_MIXED_TYPES, "");
break;
}
ErrLine = GlblLineCount;
PCurve = CagdCrvReadFromFile2(f, &ErrStr, &ErrLine);
GlblLineCount = ErrLine;
if (ErrStr != NULL) {
ParserError(DP_ERR_CAGD_LIB_ERR, ErrStr);
break;
}
PCurve -> Pnext = PObj -> U.Crv.Crv;
PObj -> U.Crv.Crv = PCurve;
break;
default:
ParserError(DP_ERR_UNDEF_EXPR_HEADER, StringToken);
break;
} /* Of switch. */
} /* Of while. */
UnGetToken(StringToken);
}
/*****************************************************************************
* Routine to unget one token (on stack of UNGET_STACK_SIZE levels!) *
*****************************************************************************/
static void UnGetToken(char *StringToken)
{
if (GlblToken >= UNGET_STACK_SIZE)
FatalError("Parser Internal stack overflow...\n");
strcpy(GlblStringToken[GlblToken], StringToken);
GlblToken++; /* GlblToken exists - Something in it (no overflow check). */
}
/*****************************************************************************
* Routine to get the next token out of the input file f. *
* Returns the next token found, as StringToken. *
* Note: StringToken must be allocated before calling this routine! *
*****************************************************************************/
static void GetStringToken(FILE *f, char *StringToken)
{
int len;
char c, *LocalStringToken;
if (GlblToken) { /* get first the unget token */
GlblToken--;
strcpy(StringToken, GlblStringToken[GlblToken]);
return;
}
/* skip white spaces: */
while ((!feof(f))
&& (((c = getc(f)) == ' ') || (c == '\t') || (c == '\n')))
if (c == '\n') GlblLineCount++; /* Count the lines. */
LocalStringToken = StringToken;
if (c == '[') /* Its a token by itself so return it. */
*LocalStringToken++ = c; /* Copy the token into string. */
else {
if (!feof(f))
do *LocalStringToken++ = c; /* Copy the token into string. */
while ((!feof(f)) &&
((c = getc(f)) != ' ') && (c != '\t') && (c != '\n'));
if (c == '\n') ungetc(c, f); /* Save it to be counted next time. */
}
*LocalStringToken = 0; /* Put eos. */
/* The following handles the spacial case were we have XXXX] - we must */
/* split it into two token XXXX and ], UnGetToken(']') and return XXXX: */
if ((StringToken[len = strlen(StringToken)-1] == ']') && (len > 0)) {
/* Return CloseParan */
UnGetToken(&StringToken[len]); /* Save next token. */
StringToken[len] = 0; /* Set end of string on "]". */
}
}
/*****************************************************************************
* Routine to get the next token out of the input file f as token number. *
* Note: StringToken must be allocated before calling this routine! *
*****************************************************************************/
static TokenType GetToken(FILE *f, char *StringToken)
{
static int IntTokens[] = {
TOKEN_OPEN_PAREN,
TOKEN_CLOSE_PAREN,
TOKEN_VERTEX,
TOKEN_POLYGON,
TOKEN_POLYLINE,
TOKEN_OBJECT,
TOKEN_COLOR,
TOKEN_INTERNAL,
TOKEN_NORMAL,
TOKEN_PLANE,
TOKEN_CURVE,
TOKEN_SURFACE,
TOKEN_E2,
TOKEN_P2,
TOKEN_E3,
TOKEN_P3,
TOKEN_NUMBER,
TOKEN_STRING,
TOKEN_VECTOR,
TOKEN_MATRIX,
TOKEN_CTLPT,
0
};
static char *StrTokens[] = {
"[",
"]",
"VERTEX",
"POLYGON",
"POLYLINE",
"OBJECT",
"COLOR",
"INTERNAL",
"NORMAL",
"PLANE",
"CURVE",
"SURFACE",
"E2",
"P2",
"E3",
"P3",
"NUMBER",
"STRING",
"VECTOR",
"MATRIX",
"CTLPT",
NULL
};
int i;
GetStringToken(f, StringToken);
if (feof(f)) return TOKEN_EOF;
for (i = 0; StrTokens[i] != NULL; i++)
if (strcmp(StringToken, StrTokens[i]) == 0) return IntTokens[i];
return TOKEN_OTHER; /* Must be number or name. */
}
/*****************************************************************************
* Routine to read from input file f the following [ATTR ...] [ATTR ...]. *
* Note the '[' was allready read. *
* Current supported attributes: [INTERNAL] - internal edge (IRIT output). *
*****************************************************************************/
static void GetVertexAttributes(VertexStruct *PVertex, FILE *f,
int *HasNormal)
{
int i;
char StringToken[LINE_LEN];
do {
switch (GetToken(f, StringToken)) {
case TOKEN_INTERNAL:
if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN)
ParserError(DP_ERR_CLOSE_PAREN_EXPECTED, StringToken);
SET_INTERNAL_EDGE(PVertex);
break;
case TOKEN_NORMAL:
/* The following handles reading 3 coord. of vertex normal. */
for (i = 0; i < 3; i++)
GetNumericToken(f, &PVertex -> Normal[i]);
GetCloseParenToken(f);
*HasNormal = TRUE;
break;
default: /* Ignore this option! */
while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN);
break;
}
}
while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
UnGetToken(StringToken);
}
/*****************************************************************************
* Routine to read from input file f the following [ATTR ...] [ATTR ...]. *
* Note the '[' was allready read. *
* Current supported attributes: [PLANE A B C D]. *
*****************************************************************************/
static void GetPolygonAttributes(PolygonStruct *PPolygon, FILE *f,
int *HasPlane)
{
int i;
char StringToken[LINE_LEN];
do {
switch (GetToken(f, StringToken)) {
case TOKEN_PLANE:
/* The following handles reading of 4 coord. of plane eqn.. */
for (i = 0; i < 4; i++)
GetNumericToken(f, &PPolygon -> Plane[i]);
GetCloseParenToken(f);
*HasPlane = TRUE;
break;
default:
while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN);
break;
}
}
while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
UnGetToken(StringToken);
}
/*****************************************************************************
* Routine to read from input file f the following [ATTR ...] [ATTR ...]. *
* Note the '[' was allready read. *
* Current supported attributes: [COLOR C] - set color. *
* All other attributes are treated as String attributes. *
*****************************************************************************/
static void GetObjectAttributes(ObjectStruct *PObject, FILE *f)
{
int i;
char StringToken[LINE_LEN], Data[LINE_LEN], Name[LINE_LEN];
do {
switch (GetToken(f, StringToken)) {
case TOKEN_COLOR:
GetToken(f, StringToken);
if (sscanf(StringToken, "%d", &i) != 1)
ParserError(DP_ERR_NUMBER_EXPECTED, StringToken);
GetCloseParenToken(f);
SetObjectColor(PObject, i);
break;
default:
strcpy(Name, StringToken);
strcpy(Data, " ");
while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN) {
strcat(Data, StringToken);
strcat(Data, " ");
}
SetObjectStrAttrib(PObject, Name, Data);
break;
}
}
while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
UnGetToken(StringToken);
}
/*****************************************************************************
* Routine to read poly* vertex information. *
*****************************************************************************/
static void GetPointData(FILE *f, PolygonStruct *PPolygon, int IsPolyline,
int *HasNormal)
{
int i, j, Length;
char StringToken[LINE_LEN];
VertexStruct *V,
*VTail = NULL;
if (GetToken(f, StringToken) != TOKEN_OTHER ||
sscanf(StringToken, "%d", &Length) != 1)
ParserError(DP_ERR_NUMBER_EXPECTED, StringToken);
for (i = 0; i < Length; i++) {
if (GetToken(f, StringToken) != TOKEN_OPEN_PAREN)
ParserError(DP_ERR_OPEN_PAREN_EXPECTED, StringToken);
V = AllocVertex(0, 0, NULL, NULL);
/* The following handle the optional attributes in struct. */
*HasNormal = FALSE;
if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
GetVertexAttributes(V, f, HasNormal);
else
UnGetToken(StringToken);
for (j = 0; j < 3; j++) /* Read coordinates. */
GetNumericToken(f, &V -> Pt[j]);
GetCloseParenToken(f);
if (!*HasNormal)
PT_COPY(V -> Normal, PPolygon -> Plane);
if (VTail == NULL)
PPolygon -> V = VTail = V;
else {
VTail -> Pnext = V;
VTail = V;
}
}
VTail -> Pnext = IsPolyline ? NULL : PPolygon -> V;
GetCloseParenToken(f);
}
/*****************************************************************************
* Routine to update the Plane equation of the given polygon by the order *
* of the first 3 vertices of that polygon. *
*****************************************************************************/
static void DPUpdatePolyPlane(PolygonStruct *PPoly)
{
int i;
VectorType V1, V2;
RealType Len;
VertexStruct *V;
V = PPoly -> V; PT_SUB(V1, V -> Pt, V -> Pnext -> Pt);
V = V -> Pnext; PT_SUB(V2, V -> Pt, V -> Pnext -> Pt);
PPoly -> Plane[0] = V1[1] * V2[2] - V2[1] * V1[2];
PPoly -> Plane[1] = V1[2] * V2[0] - V2[2] * V1[0];
PPoly -> Plane[2] = V1[0] * V2[1] - V2[0] * V1[1];
PPoly -> Plane[3] = (-DOT_PROD(PPoly -> Plane, PPoly -> V -> Pt));
/* Normalize the plane such that the normal has length of 1: */
Len = PT_LENGTH(PPoly -> Plane);
for (i = 0; i < 4; i++) PPoly -> Plane[i] /= Len;
}
/*****************************************************************************
* Routine to print pasring error according to ErrNum and set GlblParserError.*
*****************************************************************************/
static void ParserError(DataPrsrErrType ErrNum, char *Msg)
{
DPGlblLineCount = GlblLineCount;
DPGlblParserError = ErrNum;
strcpy(DPGlblTokenError, Msg); /* Keep the message in safe place... */
longjmp(LclLongJumpBuffer, 1); /* Jump to... */
}
/*****************************************************************************
* Returns TRUE if error happened, FALSE otherwise. *
* If error, then ErrorMsg is updated to point on static str describing it. *
*****************************************************************************/
int DataPrsrParseError(char **ErrorMsg)
{
DataPrsrErrType Temp;
char TempCopy[LINE_LEN];
if ((Temp = DPGlblParserError) == DP_NO_ERR) return FALSE;
strcpy(TempCopy, DPGlblTokenError);
DPGlblParserError = DP_NO_ERR;
switch (Temp) {
case DP_ERR_NUMBER_EXPECTED:
sprintf(DPGlblTokenError, "Line %d: Numeric data expected - found %s",
DPGlblLineCount, TempCopy);
break;
case DP_ERR_OPEN_PAREN_EXPECTED:
sprintf(DPGlblTokenError, "Line %d: '[' expected - found '%s'",
DPGlblLineCount, TempCopy);
break;
case DP_ERR_CLOSE_PAREN_EXPECTED:
sprintf(DPGlblTokenError, "Line %d: ']' expected - found '%s'",
DPGlblLineCount, TempCopy);
break;
case DP_ERR_LIST_COMP_UNDEF:
sprintf(DPGlblTokenError, "Line %d: Undefined list element - \"%s\"",
DPGlblLineCount, TempCopy);
break;
case DP_ERR_UNDEF_EXPR_HEADER:
sprintf(DPGlblTokenError, "Line %d: Undefined TOKEN - \"%s\"",
DPGlblLineCount, TempCopy);
break;
case DP_ERR_PT_TYPE_EXPECTED:
sprintf(DPGlblTokenError, "Line %d: Point type expected",
DPGlblLineCount);
break;
case DP_ERR_OBJECT_EMPTY:
sprintf(DPGlblTokenError, "Line %d: Empty object found",
DPGlblLineCount);
break;
case DP_ERR_EMPTY_NAME:
sprintf(DPGlblTokenError, "Given file name is empty");
break;
case DP_ERR_OPEN_FAILED:
sprintf(DPGlblTokenError, "Fail to open file - %s", TempCopy);
break;
case DP_ERR_MIXED_TYPES:
sprintf(DPGlblTokenError,
"Line %d: Mixed data types in same object",
DPGlblLineCount);
break;
case DP_STR_NOT_IN_QUOTES:
sprintf(DPGlblTokenError,
"Line %d: String not in quotes (%s)",
DPGlblLineCount, TempCopy);
break;
case DP_ERR_CAGD_LIB_ERR:
sprintf(DPGlblTokenError, "Line %d: %s",
DPGlblLineCount, TempCopy);
break;
default:
sprintf(DPGlblTokenError,
"Line %d: Data file parser - undefined error",
DPGlblLineCount);
break;
}
*ErrorMsg = DPGlblTokenError;
return TRUE;
}